import utils from '../utils';
import doAlign from './align';

/**
 * 该函数用于将一个元素（el）的某个点与目标点（tgtPoint）按照指定的对齐方式（align）进行对齐。
 * 它实际上是将目标点视为一个零宽高的区域（即一个点），然后调用 doAlign函数来实现对齐。
 *
 * @param el: 需要被对齐的DOM元素。
 * @param tgtPoint: 目标点，可以是一个包含pageX和pageY属性的对象（表示相对于文档的坐标），也可以是一个包含clientX和clientY属性的对象（表示相对于视口的坐标）。
 *                  `tgtPoint`: { pageX, pageY } or { clientX, clientY }.
 * @param align: 对齐配置对象，至少包含points属性（指定元素上的哪个点与目标点对齐）和其他可选配置（如偏移量等）。
 * If client position provided, will internal convert to page position.
 */
function alignPoint(el, tgtPoint, align) {
  let pageX;
  let pageY;

  // 1. 获取文档和窗口对象
  const doc = utils.getDocument(el);
  const win = doc.defaultView || doc.parentWindow;

  // 2. 获取窗口的滚动位置和视口尺寸
  const scrollX = utils.getWindowScrollLeft(win);
  const scrollY = utils.getWindowScrollTop(win);
  const viewportWidth = utils.viewportWidth(win);
  const viewportHeight = utils.viewportHeight(win);

  // 3. 计算目标点的页面坐标（pageX, pageY）
  // 如果目标点提供了pageX和pageY（相对于整个文档的坐标），则直接使用；否则，使用clientX和clientY（相对于视口的坐标）加上滚动位置得到页面坐标。
  if ('pageX' in tgtPoint) {
    pageX = tgtPoint.pageX;
  } else {
    pageX = scrollX + tgtPoint.clientX;
  }

  if ('pageY' in tgtPoint) {
    pageY = tgtPoint.pageY;
  } else {
    pageY = scrollY + tgtPoint.clientY;
  }

  // 4. 创建目标区域对象
  const tgtRegion = {
    left: pageX,
    top: pageY,
    width: 0,
    height: 0,
  };

  // 5. 判断目标点是否在视口内
  const pointInView =
    pageX >= 0 &&
    pageX <= scrollX + viewportWidth &&
    pageY >= 0 &&
    pageY <= scrollY + viewportHeight;

  // 6. 设置对齐点
  // Provide default target point
  const points = [align.points[0], 'cc'];

  // 调用doAlign进行对齐
  // 将目标区域（即那个点）、修改后的对齐配置（将目标点固定为'cc'）以及目标点是否可见的信息传递给doAlign函数，实现最终的对齐。
  return doAlign(el, tgtRegion, { ...align, points }, pointInView);
}

export default alignPoint;
